<?php

namespace IYUU\sdk\CoolQ;

use IYUU\sdk\CoolQ\Event\Message as EventMessage;

/**
 * 模块消息处理器，抽象类
 * Class ModulesInterface
 * @package IYUU\sdk\CoolQ
 */
abstract class ModulesProcessor
{
    /**
     * 本次对话是否为上下文响应对话, 如果当前对话是由上下文锁定而路由到的. 此值为 true, 否则为 false
     * - 此值只在__construct方法内由外部初始化，子类不可以修改；只能用inContext()方法读取
     * @access private
     * @var bool
     */
    private $inContext;

    /**
     * 构造函数
     * ModulesProcessor constructor.
     * @param bool $inContext 本次对话是否为上下文响应对话
     */
    final public function __construct(bool $inContext = false)
    {
        $this->inContext = $inContext;
        $this->init();
    }

    /**
     * 子类的初始化方法
     * - 可由开发人员根据需要重载
     * - 此方法会在构造方法(__construct)运行之后被调用
     */
    protected function init()
    {
    }

    /**
     * 应答方法 （抽象方法，子类必须实现）
     * @param Context $context
     * @param EventMessage $msgObj
     * @return array|string 提高兼容性
     */
    abstract public function respond(Context $context, EventMessage $msgObj);

    /**
     * 本次对话是否为上下文响应对话, 如果当前对话是由上下文锁定而路由到的. 此值为 true, 否则为 false
     * @return bool
     */
    final protected function inContext(): bool
    {
        return $this->inContext;
    }

    /**
     * 获取上下文Session数据
     * @return array
     */
    final protected function getContextSession(): array
    {
        $context = getContext();
        return $context->getSession(Context::moduleInContextSession, []);
    }

    /**
     * 锁定上下文会话
     * - 请在模块处理程序中调用此函数开始一个新的上下文对话，附加的参数 $expire 说明本次会话的失效时间.
     * @param int $expire
     */
    final protected function beginContext(int $expire = 120): void
    {
        $context = getContext();
        $ruleKeyword = $context->getSession(Context::moduleRuleKeywordSession);
        $module = $ruleKeyword['module'] ?? 'null';
        $inContext = [
            'module' => $module,
            'expire' => $expire + BOT_REQUEST_TIME
        ];
        $context->setSession(Context::moduleInContextSession, $inContext);
    }

    /**
     * 解锁上下文会话
     */
    final protected function endContext(): void
    {
        $context = getContext();
        $context->unsetSession(Context::moduleInContextSession);
    }

    /**
     * 在模块处理程序中调用 refreshContext 来刷新用户处于上下文的时限. 超过时限用户将会自动退出上文环境
     * @param int $expire
     * @param array $data
     */
    final protected function refreshContext(int $expire = 120, array $data = []): void
    {
        $context = getContext();
        $inContext = $context->getSession(Context::moduleInContextSession);
        if ($inContext) {
            // 刷新上下文的时限
            $inContext['expire'] = $expire + BOT_REQUEST_TIME;
            // 刷新的数据
            if (!empty($data)) {
                $inContext['data'] = $data;
            }

            $context->setSession(Context::moduleInContextSession, $inContext);
        }
    }
}
